package com.ziytek.web.citizen.service.impl;

import com.ziytek.web.citizen.caffeine.CaffeinePut;
import com.ziytek.web.citizen.config.ConfigInit;
import com.ziytek.web.citizen.constant.NumConstant;
import com.ziytek.web.citizen.constant.SettingConstant;
import com.ziytek.web.citizen.enums.ResponseEnum;
import com.ziytek.web.citizen.mapper.BasicCabinetIpMapper;
import com.ziytek.web.citizen.mapper.LocalCapacityMapper;
import com.ziytek.web.citizen.mapper.UpdateBatchWrapper;
import com.ziytek.web.citizen.model.bean.BatteryLevelDetailsData;
import com.ziytek.web.citizen.model.bean.LocalCapacityProtocol;
import com.ziytek.web.citizen.model.rsp.UnifyResponse;
import com.ziytek.web.citizen.pojo.LocalCapacityTable;
import com.ziytek.web.citizen.service.itf.BatteriesDetailsService;
import com.ziytek.web.citizen.service.itf.LocalCapacityService;
import com.ziytek.web.citizen.util.CabinetNoUtil;
import com.ziytek.web.citizen.util.HexUtil;
import com.ziytek.web.citizen.util.StringUtil;
import com.ziytek.web.citizen.util.XorDataUtils;
import io.netty.buffer.Unpooled;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * @author fenghx
 * @version 1.0
 * @className LocalCapacityServiceImpl
 * Description:
 * @date 2024/5/21 11:38
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class LocalCapacityServiceImpl implements LocalCapacityService {
    private final ConfigInit configInit;
    private final BasicCabinetIpMapper cabinetIpMapper;
    private final LocalCapacityMapper localCapacityMapper;
    private final BatteriesDetailsService batteriesDetailsService;
    private final CaffeinePut caffeinePut;

    @Override
    public void localCapacityQuery(String cabinetNo) {
        if (StringUtil.isEmpty(cabinetNo)) {
            return;
        }

        cabinetNo = StringUtil.isNumeric(cabinetNo) ? Integer.toHexString(StringUtil.toInt(cabinetNo)) : cabinetNo;
        cabinetNo = CabinetNoUtil.getCabinetNo(cabinetNo);
        var cabinetIp = cabinetIpMapper.queryByCabinetNo(cabinetNo, SettingConstant.IS_AVAILABLE);
        if (cabinetIp == null || StringUtil.isEmpty(cabinetIp.getIp())) {
            log.error("本地分容结果查询指令下发失败[{}]号机柜网络配置信息查询不存在", cabinetNo);
            return;
        }

        var sendData = getLocalCapacityQuerySendData(cabinetNo);
        if (StringUtil.isEmpty(sendData)) {
            log.error("本地分容结果查询指令下发,[{}]指令下发下发失败send长度不对 [{}]", cabinetNo, sendData);
            return;
        }

        log.info("本地分容结果查询指令下发,[{}]指令下发[{}]", cabinetNo, sendData);
        try {
            // 本地分容结果查询指令下发
            //ChannelHandlerContext ctx = IpCacheManager.getChannelHandlerContext(cabinetIp.getIp());
            var ctx = caffeinePut.getChannelContext(cabinetIp.getIp());
            if (!configInit.isTest() && ctx != null) {
                ctx.writeAndFlush(Unpooled.buffer().writeBytes(HexUtil.hexString2Bytes(sendData)));
            }
        } catch (Exception e) {
            log.error("本地分容结果查询指令下发,[{}]指令下发下发失败Charge and discharge control command issued [{}] ", cabinetNo, sendData, e);
        }
    }

    @Override
    public UnifyResponse localDeviceCapacityIssued(String cabinetNo) {
        var response = new UnifyResponse();
        response.setRetCode(ResponseEnum.OTHER.getCode());
        response.setRetMsg(ResponseEnum.OTHER.getDesc());
        if (StringUtil.isEmpty(cabinetNo)) {
            return response;
        }

        cabinetNo = StringUtil.isNumeric(cabinetNo) ? Integer.toHexString(StringUtil.toInt(cabinetNo)) : cabinetNo;
        cabinetNo = CabinetNoUtil.getCabinetNo(cabinetNo);
        var cabinetIp = cabinetIpMapper.queryByCabinetNo(cabinetNo, SettingConstant.IS_AVAILABLE);
        if (cabinetIp == null || StringUtil.isEmpty(cabinetIp.getIp())) {
            log.error("本地分容结果查询指令下发失败[{}]号机柜网络配置信息查询不存在", cabinetNo);
            return response;
        }

        var sendData = getLocalCapacityQuerySendData(cabinetNo);
        if (StringUtil.isEmpty(sendData)) {
            log.error("本地分容结果查询指令下发,[{}]指令下发下发失败send长度不对 [{}]", cabinetNo, sendData);
            return response;
        }

        log.info("本地分容结果查询指令下发,[{}]指令下发[{}]", cabinetNo, sendData);
        try {
            // 本地分容结果查询指令下发
            //ChannelHandlerContext ctx = IpCacheManager.getChannelHandlerContext(cabinetIp.getIp());
            var ctx = caffeinePut.getChannelContext(cabinetIp.getIp());
            if (!configInit.isTest() && ctx != null) {
                ctx.writeAndFlush(Unpooled.buffer().writeBytes(HexUtil.hexString2Bytes(sendData)));
            }
        } catch (Exception e) {
            log.error("本地分容结果查询指令下发,[{}]指令下发下发失败Charge and discharge control command issued [{}] ", cabinetNo, sendData, e);
            return response;
        }

        response.setRetCode(ResponseEnum.SUCCESS.getCode());
        response.setRetMsg(ResponseEnum.SUCCESS.getDesc());
        return response;
    }

    @Override
    public void localCapacityProcess(String cabinetNo, String data) {
        Map<String, Float> capacityMap;
        long start = System.currentTimeMillis();
        try {
            capacityMap = batteriesDetailsService.getAllCapacityDetails(data, cabinetNo);
        } catch (Exception e) {
            log.error("capacityProcess error:", e);
            return;
        }

        if (CollectionUtils.isEmpty(capacityMap)) {
            log.info("capacityMap is empty");
            return;
        }

        List<LocalCapacityTable> insertList = new ArrayList<>();
        List<LocalCapacityTable> updateList = new ArrayList<>();
        for (var entry : capacityMap.entrySet()) {
            var detailsData = localCapacityMapper.findByCabinetNoAndKey(cabinetNo, entry.getKey());
            if (detailsData == null) {
                detailsData = new LocalCapacityTable();
                detailsData.setCabinetNo(cabinetNo);
                detailsData.setKey(entry.getKey());
                detailsData.setCreateTime(System.currentTimeMillis());
                detailsData.setCapacity(entry.getValue());
                detailsData.setUpdateTime(System.currentTimeMillis());
                insertList.add(detailsData);
                continue;
            }
            detailsData.setCapacity(entry.getValue());
            detailsData.setUpdateTime(System.currentTimeMillis());
            updateList.add(detailsData);
        }


        // 新增记录数据
        if (!CollectionUtils.isEmpty(insertList)) {
            var result = localCapacityMapper.insertBatchSomeColumn(insertList);
            log.info("新增本地容量数据记录数据:{}", result);
        }
        // 更新记录数据
        if (!CollectionUtils.isEmpty(updateList)) {
            var result = localCapacityMapper.updateBatchById(updateList,
                    new UpdateBatchWrapper<LocalCapacityTable>()
                            .setUpdateFields(LocalCapacityTable::getUpdateTime
                                    , LocalCapacityTable::getCapacity));
            log.info("更新本地容量数据数据:{}", result);
        }

        log.info("机柜[{}]笔本地容量数据处理完成,新增[{}]条,更新[{}]条,总耗时: {}ms", cabinetNo, insertList.size(), updateList.size(), System.currentTimeMillis() - start);
    }

    @Override
    public List<BatteryLevelDetailsData> localCapacityQueryByCabinetNo(String cabinetNo) {
        if (StringUtil.isEmpty(cabinetNo)) {
            return Collections.emptyList();
        }

        var list = localCapacityMapper.findByCabinetNoAndCapacityBetweenOrderByCreatedTime(cabinetNo, NumConstant.FLOAT_ZER, NumConstant.FLOAT_TEN_THOUSAND);
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }

        List<BatteryLevelDetailsData> result = new ArrayList<>();

        for (var data : list) {
            var detailsData = new BatteryLevelDetailsData();
            detailsData.setNo(data.getKey());
            detailsData.setCap(data.getCapacity());
            detailsData.setV(NumConstant.FLOAT_ZER);
            result.add(detailsData);
        }

        return result;
    }


    private String getLocalCapacityQuerySendData(String cabinetNo) {
        if (StringUtil.isEmpty(cabinetNo)) {
            return null;
        }

        var protocol = new LocalCapacityProtocol();
        protocol.setBoardAddress(cabinetNo);

        var xorData = protocol.getHeader()
                + protocol.getBoardAddress() + protocol.getDataType()
                + protocol.getDataLen();
        var xor = XorDataUtils.getXor(xorData.getBytes(StandardCharsets.UTF_8));
        protocol.setXor(xor.trim());

        return protocol.getAllData().replaceAll(" ", "");
    }
}
